function opts = slcompactopts(opts, str, allow_extra)
%SLCOMPACTOPTS Extracts options from compact string representation
%
% [ Syntax ]
%   - opts = slcompactopts(opts, str)
%   - opts = slcompactopts(opts, str, true)
%
% [ Description ]
%   - opts = slcompactopts(opts, str) extracts logical options from 
%     compact string representation from str, and updates the options.
%
%     The compact string representation is a compact way to specify
%     a set of logical options. It uses | to separate option terms,
%     an - to turn off a term. No space is allowed.
%   
%     For example, 'a1|a2|-a3' means to turn on a1, a2, and turn off
%     a3 based on the input opts.
%
%     By default, only the fields appearing in input opts are allowed
%     to be specified in the string, otherwise, an error is raised.
%
%   - opts = slcompactopts(opts, str, true) extracts logical options
%     from compact string representation with extra fields not appearing
%     in input opts allowed. If these options turn up in str, then they
%     will be added to the opts.
%
% [ History ]
%   - Created by Dahua Lin, on Dec 24, 2007
%

%% parse and verify input arguments

assert(isstruct(opts), ...
    'sltoolbox:slcompactopts:invalidarg', ...
    'opts should be a struct.');

assert(isempty(str) || ischar(str), ...
    'sltoolbox:slcompactopts:invalidarg', ...
    'str should be either empty or a string.');

if nargin < 3
    allow_extra = false;
end

%% main

if isempty(str)
    return;
end

% extract terms
terms = strread(str, '%s', 'delimiter', '|');

% set options

for i = 1 : length(terms)
    
    t = terms{i};
    if t(1) ~= '-'
        v = true;
        tn = t;
    else
        v = false;
        tn = t(2:end);
    end
    
    if ~allow_extra && ~isfield(opts, tn)
        error('%s is not an admissible option name', tn);
    end
    
    opts.(tn) = v;            
end


    
